/**
 * Author : Fengyuan(Franklin) Zhang
 * Date : 2019/1/25
 * Description : Task control
 */

var ServiceServer = require('modelservicesdk');
var ControlBase = require('./controlBase');
var TaskModel = require('../models/task');
// var ServerCtrl = require('./servers');
// modify by qingbin
var CommonService = require('../service/CommonService');
var Schedule = require('node-schedule');

var TaskCtrl = function() {};
TaskCtrl.__proto__ = ControlBase;
TaskCtrl.model = TaskModel;

module.exports = TaskCtrl;

TaskCtrl.init = function () {
    global.taskPolling = [];
}

TaskCtrl.finished = function (params) {
    
}

//! get all the Inited status task by t_server, and the t_type is 2, represent the network environment
TaskCtrl.getByServerAndInitdStatus = function(server_id, callback){
    let t_type = 2;
    TaskModel.getByServerAndStatus(server_id, 'Inited', t_type, this.returnFunction(callback, 'Error in getting tasks by server id and inited status'));
}

//! get the number of all the Started status task
TaskCtrl.getByStartedStatus = function(callback){
    TaskModel.getAllByStatus('Started', function(err,tasks){
        if(err){
            return callback(err);
        }
        return callback(null, tasks.length);
    })
}


// get all the Started task by t_server
TaskCtrl.getAllByServerAndStartedStatus = function(server_id,pid,callback){
    TaskModel.getAllByServerAndStatus(server_id,function(err,tasks){
        if(err){
            return callback(err);
        }
        // get the sucessful and failed count by given task
        TaskModel.getAllByServerWithPidAndStatus(server_id,pid,'Finish', function(err, success){
            if(err){
                return callback(null, {
                    task: tasks.length,
                    reliability: 1
                });
            }
            TaskModel.getAllByServerWithPidAndStatus(server_id,pid,'Failed', function(err, fail){
                if(err){
                    return callback(null, {
                        task: tasks.length,
                        reliability: 1
                    });
                }
                var sum = success.length + fail.length;
                if(sum != 0){
                    let reliability = success.length / sum;
                    return callback(null, {
                        task: tasks.length,
                        reliability: reliability
                    });
                }else {
                    return callback(null, {
                        task: tasks.length,
                        reliability: 1
                    });
                }
            })
        })

       
    })
}

//! get all waiting tasks
TaskCtrl.getAllInitedTasks = function(callback){
    TaskModel.getAllByStatus('Inited', this.returnFunction(callback, 'Error in getting all inited tasks'));
}

//! rescheduling for the task
TaskCtrl.rescheduling = function(){
    var rule = new Schedule.RecurrenceRule();
    // rule.minute = [0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58];
    rule.minute = [0];
    Schedule.scheduleJob(rule, ()=>{
        //! reschedule the tasks (by 7bin)
        TaskCtrl.reschedulingFunction2();

    });
}

//任务重分配代码块 思路1: 查task表Finished任务的server(写到一半感觉这种思路不对,做了测试没有重新分配的任务)
/*TaskCtrl.reschedulingFunction1 = function (){

    // 查Task表，运行时间大于两小时的就重分配
    TaskModel.getAllInitedAndStartedTasks((err, docs) => {
        let tasksByStatus = docs;
        if (err){
            console.log("getAllInitedAndStartedTasks error:" + err.message);
            return;
        }
        let count = 0;
        // 找到这个任务的PID
        for (let task of tasksByStatus) {
            console.log(++count);
            let pendingPid = task.t_pid;
            // let pendingPid = "069e1d69934bdf131cc5b38825c7990d";
            // 遍历Task表中 t_pid = pendingPid 并且 t_status = Finished 的记录并返回

            TaskModel.getAllFinishedTasksByPid(pendingPid,async (err, docs) => {
                if (err){
                    console.log("getAllFinishedTasksByPid error:" + err.message);
                    return;
                }


                // 在task表中没找到返回error
                if (docs.length === 0) {
                    console.log("we don't find any eligible task --- taskId:" + task._id);
                    return;
                }


                //得到该模型跑成功的服务器
                let eligibleTask = docs;
                let serverArr = [];
                for (let t of eligibleTask) {
                    serverArr.push(t.t_server);
                }
                // 把重复的服务器过滤掉
                serverArr = Array.from(new Set(serverArr));
                let available = [];  //可分配的服务器

                // 把异步请求封装起来
                // 获得所有模型容器服务器
                let allServers = await new Promise((resolve, reject) => {
                    // ServerCtrl.getAll((err,res) => {
                    CommonService.getAll((err,res) => {
                        if(err)
                            resolve([]);
                        if (res){
                            resolve(res);
                        }
                    })
                })
                allServers.map((value, index) => {
                    allServers[index] = value._id;
                });
                allServers = [];

                // 过滤掉未注册的服务器(该服务器是否还在数据库中)
                for (let s of serverArr) {
                    if (allServers.indexOf(s) >= 0){
                        available.push(s);
                    }
                }

                //如果没有符合条件的服务器返回错误信息
                if (available.length === 0) {
                    console.log("we don't find any available mac to run this model --- taskId:" + task._id);
                    return;
                }

                // 把任务放到符合条件的服务器上，update t_server 为该记录的t_server
                // 分配策略: 随机分配(random)
                let selectedServer = available[Math.round(Math.random()*(available.length - 1))];
                task.t_server = selectedServer;
                task.t_status = "Inited";
                task.t_datetime = new Date();
                TaskCtrl.update(task, function (err, result) {
                    if (err) {
                        console.log("update task error:" + err.message);
                        return;
                    }
                    console.log("update success rescheduling task:" + task._id + " ---- server:" + selectedServer);
                });
            });
        }
    });

}*/


//任务重分配代码块 思路2: 查server表进行分配（started才重分配，inited就kill）
TaskCtrl.reschedulingFunction2 = function (){

    console.log("task rescheduling...");

    // 查Task表，运行时间大于两小时的就重分配
    TaskModel.getAllInitedAndStartedTasks((err, docs) => {
        if (err){
            console.log("getAllInitedAndStartedTasks error:" + err.message);
            return;
        }

        // 筛选出运行时间大于两小时的任务
        let tasksByStatus = docs;
        let currentDate = new Date();
        var tasks = [];
        for (let task of tasksByStatus) {
            var time = new Date(task.t_datetime);
            var temp = (currentDate - time) / 1000 / 60;
            if (temp > (2 * 60) )
                tasks.push(task);
        }


        // let count = 0;
        // 找到这个任务的PID
        for (let task of tasks) {

            if (task.t_status == "Inited"){
                changeTaskStatus2Error(task,"kill this task because of 'inited' too long --- taskId:" + task._id);
                continue;
            }


            let pendingPid = task.t_pid;
            // let pendingPid = "069e1d69934bdf131cc5b38825c7990d";
            // 遍历Server表中pid是task的pid且服务器在线的记录
            // ServerCtrl.getByPIDWithStatus(pendingPid, true, (err, docs) => {
            CommonService.getByPIDWithStatus(pendingPid, true, (err, docs) => {
                if (err){
                    console.log("getByPIDWithStatus error:" + err.message);
                    return;
                }

                // 在server表中没找到返回error
                if (docs.length === 0) {
                    // console.log("we don't find any eligible server --- taskId:" + task._id);
                    changeTaskStatus2Error(task,"we don't find any eligible server --- taskId:" + task._id);
                    return;
                }

                // console.log(++count);

                let eligibleServer = docs;
                let serverArr = [];
                for (let s of eligibleServer) {
                    serverArr.push(s._id);
                }

                // 把任务放到符合条件的服务器上，update t_server 为该记录的t_server
                // 分配策略: 随机分配(random)
                let selectedServer = serverArr[Math.round(Math.random()*(serverArr.length - 1))];
                task.t_server = selectedServer;
                task.t_status = "Inited";
                task.t_datetime = new Date();
                TaskCtrl.update(task, function (err, result) {
                    if (err) {
                        console.log("update task error:" + err.message);
                        return;
                    }
                    console.log("update success rescheduling task:" + task._id + " ---- server:" + selectedServer);
                });



            });

            // break;
        }
    });
}

//没办法分配的任务 将状态设置为Error
var changeTaskStatus2Error = function (task, msg) {
    task.t_status = "Error";
    task.t_datetime = new Date();
    TaskCtrl.update(task, function (err, result) {
        if (err) {
            console.log("update task error:" + err.message);
            return;
        }
        console.log(msg);
    });
}

